// AlsaCore.cpp - Wrapper for ALSA library to record and play wave files

#include <iostream>
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <locale.h>
#include <assert.h>
#include <termios.h>
#include <signal.h>
#include <output.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <asm/byteorder.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libintl.h>
#include <endian.h>
#include <byteswap.h>
#include <math.h>
#include <pthread.h>
#include "gettext.h"
#include "formats.h"
#include "version.h"
#include "AlsaPlayers.h"

AlsaPcmFilePlayer::AlsaPcmFilePlayer()
{

}

AlsaPcmFilePlayer::~AlsaPcmFilePlayer()
{
}

// Play raw PCM file
int AlsaPcmFilePlayer::Play(char * filename)
{
#ifdef _DEBUG
	std::cout << "AlsaCore play raw pcm file " << filename << "\n";
#endif

	char *pcm_name = (char *)"default";
	int err;
	snd_pcm_info_t *info = NULL;
	snd_pcm_stream_t stream;
	int open_mode = 0;
	int nonblock = 0;
	FILE *pidf = NULL;

	file_type = FORMAT_RAW;
	stream = SND_PCM_STREAM_PLAYBACK;
	command = (char *)"aplay";
	rhwparams.format = SND_PCM_FORMAT_S16_LE;
	rhwparams.rate = 16000;
	rhwparams.channels = 1;

	snd_pcm_info_alloca(&info);

	err = snd_output_stdio_attach(&loghandle, stderr, 0);
	assert(err >= 0);

	err = snd_pcm_open(&handle, pcm_name, stream, open_mode);
	if (err < 0) {
		error(_("audio open error: %s"), snd_strerror(err));
		return (1);
	}

	if ((err = snd_pcm_info(handle, info)) < 0) {
		error(_("info error: %s"), snd_strerror(err));
		return (1);
	}

	if (nonblock) {
		err = snd_pcm_nonblock(handle, 1);
		if (err < 0) {
			error(_("nonblock setting error: %s"), snd_strerror(err));
			return (1);
		}
	}

	chunk_size = DEFAULT_CHUNK_SIZE;
	hwparams = rhwparams;

	audiobuf = (unsigned char *)malloc(AUDIO_BUFFER_SIZE);
	if (audiobuf == NULL) {
		error(_("not enough memory"));
		return (1);
	}

	writei_func = snd_pcm_writei;
	readi_func  = snd_pcm_readi;
	writen_func = snd_pcm_writen;
	readn_func  = snd_pcm_readn;

	if (pidfile_name) {
		errno = 0;
		pidf = fopen(pidfile_name, "w");
		if (pidf) {
			(void)fprintf (pidf, "%d\n", getpid());
			fclose(pidf);
			pidfile_written = 1;
		} else {
			error(_("Cannot create process ID file %s: %s"),
					pidfile_name, strerror (errno));
			return (1);
		}
	}

	//todo
	/*
	signal(SIGINT,  signal_handler);
	signal(SIGTERM, signal_handler);
	signal(SIGABRT, signal_handler);
	signal(SIGUSR1, signal_handler_recycle);
	*/

	PlayPcmFile(filename);

	if (verbose == 2) {
		putchar('\n');
	}

	snd_pcm_close(handle);
	handle = NULL;
	free(audiobuf);

	snd_output_close(loghandle);
	snd_config_update_free_global();

	return (EXIT_SUCCESS);
}

// Playback raw PCM file
void AlsaPcmFilePlayer::PlayPcmFile(char *name)
{
	pbrec_count = LLONG_MAX;
	fdcount = 0;
	if (!name || !strcmp(name, "-")) {
		fd = fileno(stdin);
		name = (char *)"stdin";
	} else {
		init_stdin();
		if ((fd = open(name, O_RDONLY, 0)) == -1) {
			perror(name);
			prg_exit(EXIT_FAILURE);
		}
	}

	// Allocate audio buffer with enough playback size
	unsigned char* fullaudiobuf;
	fullaudiobuf = (unsigned char *)malloc(FULL_AUDIO_BUFFER_SIZE);
	if (fullaudiobuf == NULL) {
		error(_("not enough memory"));
		exit(EXIT_FAILURE);
	}

	// Should be raw data
	init_raw_data();
	pbrec_count = calc_count();
	set_play_params();

	int read;
	off64_t c = chunk_bytes;
	int l = 0;
	do {
		read = safe_read(fd, fullaudiobuf + l, c);

		if (read < 0) {
			free(fullaudiobuf);
			close(fd);
			return;
		}

		if (read < c) {
			break;
		}

		l += read;
	}
	while ((size_t)read <= c);

	PlayPcmBuffer(fullaudiobuf, l);

	snd_pcm_nonblock(handle, 0);
	snd_pcm_drain(handle);
	snd_pcm_nonblock(handle, nonblock);
	free(fullaudiobuf);

	fprintf(stderr, "Finished play back raw PCM buffer\n");

	if (fd != 0) {
		close(fd);
	}
}

